package com.swsc.solarverse.common.util;

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;

import java.lang.reflect.Array;
import java.util.*;

/**
 * @Author chencl
 * @Date 2022/5/19 0:10
 * @Version 1.0
 * @Description
 */
public class ObjectMapper {
    private static final MapperFacade DEFAULT_MAPPER;
    /** 可处理空值 */
    private static final MapperFacade MAPPER;

    static {
        MapperFactory defaultMapperFactory = (new DefaultMapperFactory.Builder()).build();
        DEFAULT_MAPPER = defaultMapperFactory.getMapperFacade();

        MapperFactory papperFactory = (new DefaultMapperFactory.Builder()).mapNulls(false).build();
        MAPPER = papperFactory.getMapperFacade();
    }

    public ObjectMapper() {
    }

    public static <SOURCE, DESTINATION> DESTINATION map(SOURCE source, Class<DESTINATION> destinationClass) {
        return isEmpty(source) ? null : map(DEFAULT_MAPPER, source, destinationClass);
    }

    /**
     * Specify Object Type Mapping(not map null value)
     *
     * @param source
     * @param destination
     * @param <SOURCE>
     * @param <DESTINATION>
     */
    public static <SOURCE, DESTINATION> void map(SOURCE source, DESTINATION destination) {
        if(isEmpty(source) || isEmpty(destination)){
            return;
        }
        DEFAULT_MAPPER.map(source, destination);
    }

    public static <SOURCE, DESTINATION> void mapIgnoreNulls(SOURCE source, DESTINATION destination) {
        if(isEmpty(source) || isEmpty(destination)){
            return;
        }
        MAPPER.map(source, destination);
    }

    public static <SOURCE, DESTINATION> List<DESTINATION> mapList(Iterable<SOURCE> sourceList, Class<DESTINATION> destinationClass) {
        return isEmpty(sourceList) ? Collections.emptyList() : mapList(DEFAULT_MAPPER, sourceList, destinationClass);
    }

    public static <SOURCE, DESTINATION> DESTINATION map(MapperFacade mapper, SOURCE source, Class<DESTINATION> destinationClass) {
        return isEmpty(source) ? null : mapper.map(source, destinationClass);
    }

    public static <SOURCE, DESTINATION> List<DESTINATION> mapList(MapperFacade mapper, Iterable<SOURCE> sourceList, Class<DESTINATION> destinationClass) {
        return isEmpty(sourceList) ? Collections.emptyList() : mapper.mapAsList(sourceList, destinationClass);
    }

    private static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        } else if (obj instanceof Optional) {
            return !((Optional<?>) obj).isPresent();
        } else if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        } else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        } else if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        } else {
            return obj instanceof Map && ((Map) obj).isEmpty();
        }
    }
}
